﻿using Microsoft.AspNet.Identity;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
using YlisChat.DAO;
using YlisChat.Models;

namespace YlisChat.Controllers
{
    [Authorize]
    [RoutePrefix("api/UserList")]
    public class UserListController : BaseController
    {
        /// <summary>
        /// Get a list of channels where the user is joined
        /// GET api/UserList/
        /// </summary>
        /// <returns>All the channels where user is joined</returns>
        [ResponseType(typeof(List<ChannelModel>))]
        [Route("MyChannels")]
        public async Task<IHttpActionResult> GetMyChannels()
        {
            ApplicationUser user = UserManager.FindById(User.Identity.GetUserId());
            List<ChannelModel> channels = await (from usrl in db.UserList
                                                 where usrl.UserId == user.Id
                                                 join i in db.Channels on usrl.HashTag equals i.HashTag
                                                 select i).ToListAsync();
            return this.Ok(channels);
        }

        /// <summary>
        /// Get all users in a channel. User must be joined to the channel.
        /// GET: api/UserList/name
        /// </summary>
        /// <param name="name">The name of the channel</param>
        /// <returns></returns>
        [ResponseType(typeof(List<UserListViewModel>))]
        [Route("Users/{name}")]
        public async Task<IHttpActionResult> GetUsers(string name)
        {
            if (String.IsNullOrWhiteSpace(name))
                return this.BadRequest("Invalid channel name");

            // Create asynchronous tasks
            Task<ApplicationUser> FindMyselfTask = UserManager.FindByIdAsync(User.Identity.GetUserId());
            Task<List<UserListViewModel>> FindUsersTask = (from usrl in db.UserList
                                                           join i in db.Users on usrl.UserId equals i.Id
                                                           where usrl.HashTag == name
                                                           select new UserListViewModel()
                                                           {
                                                               Nick = i.UserName,
                                                               HashTag = usrl.HashTag,
                                                               Id = usrl.UserId,
                                                               AdminState = usrl.AdminState
                                                           }).ToListAsync();

            // Wait for tasks to complete
            await Task.WhenAll(FindMyselfTask, FindUsersTask);
            List<UserListViewModel> lusers = FindUsersTask.Result;
            ApplicationUser user = FindMyselfTask.Result;

            if (lusers.Find(x => x.Id == user.Id) == default(UserListViewModel))
                return this.BadRequest("User not in a channel");

            return this.Ok(lusers);
        }

        // POST: api/UserList/Kick
        /// <summary>
        /// Kick a user from a channel
        /// </summary>
        /// <param name="user">The kicked user</param>
        [Route("Kick")]
        [HttpPost]
        public async Task<IHttpActionResult> Kick(UserList user)
        {
            if (user == null)
                return this.BadRequest("No data");

            if (!this.ValidateUser(user))
                return this.BadRequest("Invalid data");

            ApplicationUser auser = UserManager.FindById(User.Identity.GetUserId());

            // First check if current user is admin in the specified channel
            UserList luser = await (from usrl in db.UserList
                                    where usrl.HashTag == user.HashTag
                                    where usrl.UserId == auser.Id
                                    select usrl).FirstOrDefaultAsync();
            if (luser == default(UserList))
                return this.Unauthorized();
            if (luser.AdminState != AdminLevel.ADMIN)
                return this.Unauthorized();

            // Find the user to be kicked
            luser = await (from usrl in db.UserList
                           where usrl.HashTag == user.HashTag
                           where usrl.UserId == user.UserId
                           select usrl).FirstOrDefaultAsync();
            if (luser == default(UserList))
                return this.BadRequest("User not found");

            // By default one day ban
            BanList ban = new BanList()
            {
                UserId = user.UserId,
                HashTag = user.HashTag,
                Expire = DateTime.UtcNow.AddDays(1)
            };

            // Add the user to banlist
            db.Bans.Add(ban);

            // "Kick" the user
            db.UserList.Remove(luser);
            await db.SaveChangesAsync();

            // Send the kick message
            MessageDAO mdao = new MessageDAO(db);
            mdao.SendSystemMessage(String.Format("@{0} has been kicked from {1}", luser.UserId, luser.HashTag), luser.HashTag, luser.UserId);
            return this.Ok();
        }

        // PUT: api/UserList/5
        /*public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE: api/UserList/5
        public void Delete(int id)
        {

        }*/

        private bool ValidateUser(UserList user)
        {
            if (String.IsNullOrWhiteSpace(user.UserId))
                return false;

            if (String.IsNullOrWhiteSpace(user.HashTag))
                return false;

            return true;
        }
    }
}
